/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 *
 * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
 *
 * Contributor(s): 
 *  Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
 *  
 * If you didn't download this code from the following link, you should check
 * if you aren't using an obsolete version: http://www.isqlviewer.com
 */
package org.isqlviewer.sql;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Iterator;
import java.util.Vector;

import org.isqlviewer.util.LocalMessages;

/**
 * Wrapper class for generic statements produced by the underlying connection object.
 * <p>
 * 
 * @author Mark A. Kobold &lt;mkobold at isqlviewer dot com&gt;
 * @version 1.0
 */
class StatementWrapper implements Statement {

    protected static final LocalMessages messages = new LocalMessages(ConnectionWrapper.BUNDLE_NAME);
    protected Statement stmt;
    protected ConnectionWrapper connection;
    protected String lastStatement;
    protected Vector<ResultSetWrapper> openCursors = new Vector<ResultSetWrapper>();

    public StatementWrapper(ConnectionWrapper connection, Statement stmt, String currentSQL) {

        this.stmt = stmt;
        this.connection = connection;
        this.lastStatement = currentSQL;
    }

    public ConnectionWrapper getOwner() {

        return connection;
    }

    public Statement getParent() {

        return stmt;
    }

    public void close() throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setMaxRows(0);
        } catch (Throwable t) {
            error(messages.format("DataSource.GeneralMethodError", "setMaxRows()"), t);
        }
        try {
            stmt.clearWarnings();
        } catch (Throwable t) {
            error(messages.format("DataSource.GeneralMethodError", "clearWarnings()"), t);
        }
        try {
            stmt.clearBatch();
        } catch (Throwable t) {
            error(messages.format("DataSource.GeneralMethodError", "clearBatch()"), t);
        }
        if (!openCursors.isEmpty()) {
            Iterator itr = openCursors.iterator();
            warn(messages.format("DataSource.DirtyCursorsError"));
            while (itr.hasNext()) {
                ResultSetWrapper next = (ResultSetWrapper) itr.next();
                itr.remove();
                try {
                    next.close();
                } catch (Throwable t) {
                }
                try {
                    StatementWrapper ps = (StatementWrapper) next.getStatement();
                    if (ps != this) {
                        ps.stmt.close();
                    }
                } catch (Throwable t) {
                }
            }
        }
    }

    public ResultSet executeQuery(String sql) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            String nsql = connection.nativeSQL(sql);
            info(messages.format("DataSource.StatementExec", nsql));
            ResultSetWrapper wrs = new ResultSetWrapper(this, stmt.executeQuery(sql));
            openCursors.add(wrs);
            return wrs;
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeQuery(String)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeQuery(String)");
            throw sqle;
        }
    }

    public boolean execute(String sql) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.execute(sql);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getResultSet()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getResultSet()");
            throw sqle;
        }
    }

    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.execute(sql, autoGeneratedKeys);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "execute(String,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "execute(String,int)");
            throw sqle;
        }
    }

    public boolean execute(String sql, int[] columnIndexes) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.execute(sql, columnIndexes);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "execute(String,int[])"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "execute(String,int[])");
            throw sqle;
        }
    }

    public boolean execute(String sql, String[] columnNames) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.execute(sql, columnNames);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "execute(String,String[])"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "execute(String,String[])");
            throw sqle;
        }
    }

    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.executeUpdate(sql, autoGeneratedKeys);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeUpdate(String,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeUpdate(String,int)");
            throw sqle;
        }
    }

    public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.executeUpdate(sql, columnIndexes);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeUpdate(String,int[])"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeUpdate(String,int[])");
            throw sqle;
        }
    }

    public int executeUpdate(String sql, String[] columnNames) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.executeUpdate(sql, columnNames);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeUpdate(String,String[])"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeUpdate(String,String[])");
            throw sqle;
        }
    }

    public int executeUpdate(String sql) throws SQLException {

        connection.updateLastAccess();
        try {
            lastStatement = sql;
            return stmt.executeUpdate(sql);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeUpdate(String)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeUpdate(String)");
            throw sqle;
        }
    }

    public int getMaxFieldSize() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getMaxFieldSize();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getMaxFieldSize(int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getMaxFieldSize(int)");
            throw sqle;
        }
    }

    public void setMaxFieldSize(int max) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setMaxFieldSize(max);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setMaxFieldSize(int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setMaxFieldSize(int)");
            throw sqle;
        }
    }

    public int getMaxRows() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getMaxRows();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getMaxRows()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getMaxRows()");
            throw sqle;
        }
    }

    public void setMaxRows(int max) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setMaxRows(max);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setMaxRows(int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setMaxRows(int)");
            throw sqle;
        }
    }

    public void setEscapeProcessing(boolean enable) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setEscapeProcessing(enable);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setEscapeProcessing(boolean)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setEscapeProcessing(boolean)");
            throw sqle;
        }
    }

    public int getQueryTimeout() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getQueryTimeout();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getQueryTimeout()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getQueryTimeout()");
            throw sqle;
        }
    }

    public void setQueryTimeout(int seconds) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setQueryTimeout(seconds);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setQueryTimeout(int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setQueryTimeout(int)");
            throw sqle;
        }
    }

    public void cancel() throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.cancel();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "cancel()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "cancel()");
            throw sqle;
        }
    }

    public SQLWarning getWarnings() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getWarnings();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getWarnings()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getWarnings()");
            throw sqle;
        }
    }

    public void clearWarnings() throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.clearWarnings();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "clearWarnings()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "clearWarnings()");
            throw sqle;
        }
    }

    public void setCursorName(String name) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setCursorName(name);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setCursorName(String)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setCursorName(String)");
            throw sqle;
        }
    }

    public ResultSet getResultSet() throws SQLException {

        connection.updateLastAccess();
        try {
            ResultSetWrapper wrs = new ResultSetWrapper(this, stmt.getResultSet());
            openCursors.add(wrs);
            return wrs;
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getResultSet()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getResultSet()");
            throw sqle;
        }
    }

    public int getUpdateCount() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getUpdateCount();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getUpdateCount()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getUpdateCount()");
            throw sqle;
        }
    }

    public boolean getMoreResults() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getMoreResults();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getMoreResults()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getMoreResults()");
            throw sqle;
        }
    }

    public int getFetchDirection() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getFetchDirection();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getFetchDirection()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getFetchDirection()");
            throw sqle;
        }
    }

    public int[] executeBatch() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.executeBatch();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeBatch()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeBatch()");
            throw sqle;
        }
    }

    public void setFetchSize(int i) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setFetchSize(i);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setFetchSize(int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setFetchSize(int)");
            throw sqle;
        }
    }

    public void clearBatch() throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.clearBatch();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "clearBatch()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "clearBatch()");
            throw sqle;
        }
    }

    public void addBatch(String s) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.addBatch(s);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "addBatch(String)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "addBatch(String)");
            throw sqle;
        }
    }

    public int getResultSetConcurrency() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getResultSetConcurrency();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getResultSetConcurrency()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getResultSetConcurrency()");
            throw sqle;
        }
    }

    public void setFetchDirection(int i) throws SQLException {

        connection.updateLastAccess();
        try {
            stmt.setFetchDirection(i);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setFetchDirection(int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setFetchDirection(int)");
            throw sqle;
        }
    }

    public int getFetchSize() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getFetchSize();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getFetchSize()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getFetchSize()");
            throw sqle;
        }
    }

    public Connection getConnection() throws SQLException {

        return connection;
    }

    public int getResultSetType() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getResultSetType();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getResultSetType()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getResultSetType()");
            throw sqle;
        }
    }

    public ResultSet getGeneratedKeys() throws SQLException {

        connection.updateLastAccess();
        try {
            ResultSetWrapper wrs = new ResultSetWrapper(this, stmt.getGeneratedKeys());
            openCursors.add(wrs);
            return wrs;
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getGeneratedKeys()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getGeneratedKeys()");
            throw sqle;
        }
    }

    public boolean getMoreResults(int current) throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getMoreResults(current);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getMoreResults(int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getMoreResults(int)");
            throw sqle;
        }
    }

    public int getResultSetHoldability() throws SQLException {

        connection.updateLastAccess();
        try {
            return stmt.getResultSetHoldability();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getResultSetHoldability()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getResultSetHoldability()");
            throw sqle;
        }
    }

    protected void info(Object message, Throwable error) {

        connection.info(message, error);
    }

    protected void info(Object message) {

        connection.info(message);
    }

    protected void debug(Object message, Throwable error) {

        connection.trace(message, error);
    }

    protected void debug(Object message) {

        connection.trace(message);
    }

    protected void error(Object message, Throwable error) {

        connection.error(message, error);
    }

    protected void error(Object message) {

        connection.error(message);
    }

    protected void warn(Object message, Throwable error) {

        connection.warn(message, error);
    }

    protected void warn(Object message) {

        connection.warn(message);
    }

    void removeOpenCursor(ResultSetWrapper set) {

        openCursors.remove(set);
    }
}
